#pragma once 
#include<iostream>
#include<queue>
#include<pthread.h>
#include"Task.hpp"
#define NUM 6
class ThreadPool{
private:
    int _num;
    bool _stop;
    std::queue<Task> _task_queue;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;


    //单例
    ThreadPool(int num = NUM):_num(num),_stop(false)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool &){}
    static ThreadPool* single_instance;
public:
    static ThreadPool* GetInstance()
    {
        pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
        if(single_instance == nullptr)
        {
            pthread_mutex_lock(&my_mutex);
            if(single_instance == nullptr)
            {
                single_instance = new ThreadPool();
                single_instance->InitThreadPool();
            }
            pthread_mutex_unlock(&my_mutex);

        }
        return single_instance;
    }

    bool InitThreadPool()
    {
        for(int i = 0;i<_num;i++)
        {
            pthread_t tid;
            if(pthread_create(&tid, nullptr, ThreadRoutine, this)!=0)  //线程创建失败
            {
                LOG(FATAL, "create thread pool error!");
                return false;
            }
        }
        LOG(INFO, "create thread pool success!!");
        return true;

    } 


    bool IsStop()
    {
        return _stop;
    }
    bool IsQueueIsEmpty()
    {
        return _task_queue.empty();
    }
    void Lock()
    {
        pthread_mutex_lock(&_lock);

    }
    void Unlock()
    {
        pthread_mutex_unlock(&_lock);
    }
    void ThreadWait()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    void ThreadWakeup(){}

    static void *ThreadRoutine(void *args)
    {
        ThreadPool* tp = (ThreadPool*)args;
        while(true)
        {
            Task task;

            tp->Lock();
            if(tp->IsQueueIsEmpty())
            {
                tp->ThreadWait();   //让线程休眠，当我醒来，一定是占有互斥锁的
            }
            tp->PopTask(task);
            tp->Unlock();
            task.ProcessOn();
        }
    }

    void PushTask(const Task &task)   //in
    {
        Lock();
        _task_queue.push(task);
        Unlock();
        pthread_cond_signal(&_cond);
    }

    void PopTask(Task &task)    //out
    {
        task = _task_queue.front();
        _task_queue.pop();
    }

    ~ThreadPool(){
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }
};

ThreadPool* ThreadPool::single_instance;